在 JavaScript 中,使用 JSON.parse(JSON.stringify(obj)) 来实现深拷贝虽然看似简洁,但它仅适用于纯 JSON 兼容的简单数据结构。在实际开发中,这种方式存在多个严重的局限性,需要特别注意以下问题:
无法处理特定数据类型
JSON 格式本身不支持 JavaScript 中的部分特有类型,在序列化时会出现丢失或转换错误:
- 函数与 undefined:对象中包含的函数属性会被直接忽略,而值为
undefined的属性也会被删除。 - Symbol 与 BigInt:遇到这两种类型时,
JSON.stringify()会直接抛出错误。 - Date 对象:日期对象会被转换为 ISO 格式的字符串,导致克隆后的对象失去 Date 实例的功能(如
instanceof Date为 false)。 - RegExp 正则对象:正则表达式会被转换为空对象
{}。
复杂数据结构的降级
对于现代 JavaScript 中常用的内置数据结构,JSON 序列化无法正确还原:
- Map 和 Set:这些集合类型会被转换为普通的空对象
{},其内部键值对完全丢失。 - Typed Arrays 与 ArrayBuffer:带类型的数组和缓冲区无法被正确处理。
- 原型链与构造器信息丢失:该方法只能生成普通对象(plain object),所有自定义的原型、类实例以及继承关系都会被丢弃。
无法处理循环引用
当对象内部存在循环引用(例如 a.b = a)时,JSON.stringify() 会直接抛出 TypeError: Converting circular structure to JSON 错误,导致深拷贝失败。它本身不具备检测或替换循环引用的能力。
其他隐性问题
- 精度丢失:超大数字(大于 $2^{53} - 1$)在 JSON 中可能会被截断或转为科学计数法,解析后数值不再准确。
- 不可枚举属性丢失:通过
Object.defineProperty设置的不可枚举属性会被跳过。 - 特殊值过滤:
NaN和Infinity会被转换为null;键名为null或undefined的属性可能会变成字符串"null"或被忽略。
最佳实践建议
真正需要可靠的深拷贝时,建议优先使用现代浏览器及 Node.js 17+ 原生支持的 structuredClone() 方法。它能够完美处理循环引用、Date、Map、Set 等复杂类型。只有在明确知道数据仅为简单的嵌套对象/数组,且不包含上述任何特殊值时,才可以谨慎使用 JSON 方案。